package com.usefullc.user.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.usefullc.common.exception.BizException;
import com.usefullc.common.util.BeanUtils;
import com.usefullc.system.configuration.TransactionHelper;
import com.usefullc.system.entity.Pager;
import com.usefullc.system.service.AbstractBizService;
import com.usefullc.system.service.SerialNumberService;
import com.usefullc.system.service.component.SystemConfigComponent;
import com.usefullc.system.vo.TreeVo;
import com.usefullc.user.domain.AuthRes;
import com.usefullc.user.domain.Role;
import com.usefullc.user.domain.User;
import com.usefullc.user.mapper.AuthResMapper;
import com.usefullc.user.param.MenuParam;
import com.usefullc.user.query.AuthResQuery;
import com.usefullc.user.vo.RoleAuthResTreeVo;
import com.usefullc.user.vo.permission.AuthResourceVo;
import com.usefullc.user.vo.permission.MenuMetaVo;
import com.usefullc.user.vo.permission.MenuVo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;


/**
 * @author: Sampson
 * @date: 2022-01-10 14:11
 */
@Service
public class AuthResService extends AbstractBizService<AuthResMapper,AuthRes,AuthResQuery> {

    @Autowired
    private TransactionHelper transactionHelper;

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private SystemConfigComponent systemConfigComponent;

    @Autowired
    private SerialNumberService serialNumberService;



    @Override
    protected QueryWrapper<AuthRes> getQueryWrapper(AuthResQuery query) {
        QueryWrapper<AuthRes> queryWrapper = super.getQueryWrapper(query);
//        if (StringUtils.isNotEmpty(query.getCodeLike())) {
//            queryWrapper.likeRight("code",query.getCodeLike());
//        }
        return queryWrapper;
    }

    public AuthRes findByTypeAndUrl(String appType,String url){
        AuthResQuery authResQuery = new AuthResQuery();
        authResQuery.setAppType(appType);
        authResQuery.setUrl(url);
        return this.findOne(authResQuery);
    }


    public AuthResourceVo getAuthResourceByUserId(Long userId){
        AuthResourceVo authResourceVo = new AuthResourceVo();
        authResourceVo.setSysSafeMode(false);
        authResourceVo.setAuth(Lists.newArrayList());
        authResourceVo.setAllAuth(Lists.newArrayList());
        AuthResourceVo authResourceVoOfMenu = this.getMenuByUserId(userId);
        authResourceVo.setMenu(authResourceVoOfMenu.getMenu());
        authResourceVo.setAuthKeys(authResourceVoOfMenu.getAuthKeys());
        return authResourceVo;
    }




    public AuthResourceVo getMenuByUserId(Long userId) {
        AuthResourceVo authResourceVo = new AuthResourceVo();
        User user = userService.findById(userId);
        List<Role> roleList = userService.getBaseMapper().findRoleListByUserId(user.getId());
        List<AuthRes> dataList = new ArrayList<>();
        List<String> authKeys = new ArrayList<>();
        authResourceVo.setAuthKeys(authKeys);
        for (Role role : roleList) {
            //添加菜单，按钮类型不需要
            List<AuthRes> authResDBList = roleService.getBaseMapper().findAuthResListByRoleId(role.getId());
            if (CollectionUtils.isNotEmpty(authResDBList)) {
                List<AuthRes> authResList = authResDBList.stream().filter(data->data.getMenu()).collect(Collectors.toList());
                for (AuthRes authRes : authResList) {
                    if (!dataList.contains(authRes)) {
                        dataList.add(authRes);
                    }
                    if(!authKeys.contains(authRes.getId().toString())){
                        authKeys.add(authRes.getId().toString());
                    }
                }

            }
        }


        //排序
        Collections.sort(dataList, Comparator.comparingInt(AuthRes::getOrderNo));

        List<AuthRes> parentDataList = dataList.stream().filter(data -> data.getParentId() != null && data.getParentId() == 0L).collect(Collectors.toList());
        List<MenuVo> newDataList = new ArrayList<>();
        authResourceVo.setMenu(newDataList);
        if (CollectionUtils.isNotEmpty(parentDataList)) {
            for (AuthRes authRes : parentDataList) {
                MenuVo menuVo = new MenuVo();
                newDataList.add(menuVo);
                menuVo.setRedirect("");
                menuVo.setId(authRes.getId());
                menuVo.setParentId(authRes.getParentId());
                menuVo.setName(authRes.getName());
                menuVo.setPath(authRes.getUrl());
                menuVo.setComponent(authRes.getTplUrl());
                menuVo.setRoute(true);
                menuVo.setCode(authRes.getCode());
                menuVo.setIcon(StringUtils.defaultIfEmpty(authRes.getIcon()," "));
                menuVo.setMenu(authRes.getMenu());
                menuVo.setAppType(authRes.getAppType());
                menuVo.setDescription(authRes.getDescription());
                //
                MenuMetaVo menuMetaVo = new MenuMetaVo();
                menuMetaVo.setKeepAlive(false);
                menuMetaVo.setInternalOrExternal(StringUtils.equalsAnyIgnoreCase("layouts/IframePageView", authRes.getTplUrl()));
                menuMetaVo.setIcon(StringUtils.defaultIfEmpty(authRes.getIcon()," "));
                menuMetaVo.setComponentName(authRes.getTplUrl());
                menuMetaVo.setTitle(authRes.getName());
                menuVo.setMeta(menuMetaVo);

                List<MenuVo> children = new ArrayList<>();
                //获取子集
                List<AuthRes> childDataList = dataList.stream().filter(data->data.getParentId() == authRes.getId().longValue()).collect(Collectors.toList());

                setChildren(childDataList,children,menuVo);

            }
        }
        return authResourceVo;
    }

    public List<AuthRes> getChildrenByCodeLike(String codeLike) {
        AuthResQuery query = new AuthResQuery();
        query.setCodeLike(codeLike);
        query.setOrderByColumn("orderNo");
        query.setAscOrDesc("asc");
        return this.findAll(query);
    }

    public List<AuthRes> getChildrenByParentId(Long parentId) {
        AuthResQuery query = new AuthResQuery();
        query.setOrderByColumn("orderNo");
        query.setAscOrDesc("asc");
        query.setParentId(parentId);
        return this.findAll(query);
    }


    public Pager<MenuVo> listByPage(AuthResQuery query) {
        query.setParentId(0L);
        query.setOrderByColumn("orderNo");
        query.setAscOrDesc("asc");
        Pager<AuthRes> pager = this.findByPage(query);
        List<AuthRes> dataList = pager.getDataList();
        Pager<MenuVo> newPager = new Pager<>(pager);
        List<MenuVo> newDataList = new ArrayList<>();
        newPager.setDataList(newDataList);
        if (CollectionUtils.isNotEmpty(dataList)) {
            for (AuthRes authRes : dataList) {
                MenuVo menuVo = new MenuVo();
                newDataList.add(menuVo);
                menuVo.setRedirect("");
                menuVo.setId(authRes.getId());
                menuVo.setParentId(authRes.getParentId());
                menuVo.setName(authRes.getName());
                menuVo.setPath(authRes.getUrl());
                menuVo.setComponent(authRes.getTplUrl());
                menuVo.setRoute(true);
                menuVo.setCode(authRes.getCode());
                menuVo.setIcon(StringUtils.defaultIfEmpty(authRes.getIcon()," "));
                menuVo.setDescription(authRes.getDescription());
                menuVo.setMenu(authRes.getMenu());
                menuVo.setAppType(authRes.getAppType());
                menuVo.setOrderNo(authRes.getOrderNo());
                //
                MenuMetaVo menuMetaVo = new MenuMetaVo();
                menuMetaVo.setKeepAlive(false);
                menuMetaVo.setInternalOrExternal(StringUtils.equalsAnyIgnoreCase("layouts/IframePageView", authRes.getTplUrl()));
                menuMetaVo.setIcon(authRes.getIcon());
                menuMetaVo.setIcon(StringUtils.defaultIfEmpty(authRes.getIcon()," "));
                menuMetaVo.setComponentName(authRes.getTplUrl());
                menuMetaVo.setTitle(authRes.getName());
                menuVo.setMeta(menuMetaVo);

                List<MenuVo> children = new ArrayList<>();
                //获取子集
                List<AuthRes> childDataList = getChildrenByCodeLike(authRes.getCode());

                setChildren(childDataList,children,menuVo);

            }
        }
        return newPager;
    }

    private void setChildren(List<AuthRes> childDataList, List<MenuVo> children, MenuVo menuVo){
        for (AuthRes authRes : childDataList) {
            if (authRes.getParentId() != menuVo.getId().longValue()) {
                continue;
            }
            MenuVo childMenuVo = new MenuVo();
            childMenuVo.setRedirect("");
            childMenuVo.setId(authRes.getId());
            childMenuVo.setParentId(authRes.getParentId());
            childMenuVo.setName(authRes.getName());
            childMenuVo.setPath(authRes.getUrl());
            childMenuVo.setComponent(authRes.getTplUrl());
            childMenuVo.setCode(authRes.getCode());
            childMenuVo.setRoute(true);
            childMenuVo.setIcon(StringUtils.defaultIfEmpty(authRes.getIcon()," "));
            childMenuVo.setDescription(authRes.getDescription());
            childMenuVo.setMenu(authRes.getMenu());
            childMenuVo.setAppType(authRes.getAppType());
            childMenuVo.setOrderNo(authRes.getOrderNo());
            //
            MenuMetaVo menuMetaVo = new MenuMetaVo();
            menuMetaVo.setKeepAlive(false);
            menuMetaVo.setInternalOrExternal(StringUtils.equalsAnyIgnoreCase("layouts/IframePageView", authRes.getTplUrl()));
            menuMetaVo.setIcon(StringUtils.defaultIfEmpty(authRes.getIcon()," "));
            menuMetaVo.setComponentName(authRes.getTplUrl());
            menuMetaVo.setTitle(authRes.getName());
            childMenuVo.setMeta(menuMetaVo);

            children.add(childMenuVo);

            List<MenuVo> subChildren = new ArrayList<>();
            setChildren(childDataList,subChildren,childMenuVo);
        }
        if(children.size() > 0){
            menuVo.setChildren(children);
        }
    }

    public List<TreeVo> listTree(AuthResQuery query){
        query.setParentId(0L);
        query.setOrderByColumn("orderNo");
        query.setAscOrDesc("asc");
        List<AuthRes> dataList = this.findAll(query);
        List<TreeVo> newDataList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(dataList)) {
            for (AuthRes authRes : dataList) {
                TreeVo treeVo = new TreeVo();
                newDataList.add(treeVo);
                treeVo.setTitle(authRes.getName());
                treeVo.setValue(authRes.getId().toString());
                treeVo.setKey(authRes.getId().toString());
                List<TreeVo> children = new ArrayList<>();
                //获取子集
                List<AuthRes> childDataList = getChildrenByCodeLike(authRes.getCode());

                setTreeChildren(childDataList,children,treeVo);
            }
        }
        return newDataList;
    }

    public RoleAuthResTreeVo getAuthResTreeVoByRoleId(Long roleId){
        RoleAuthResTreeVo roleAuthResTreeVo = new RoleAuthResTreeVo();
        List<TreeVo> treeVoList = this.listTree(new AuthResQuery());
        roleAuthResTreeVo.setTreeVoList(treeVoList);

        Role role = roleService.findById(roleId);
        List<AuthRes> authResDBList = roleService.getBaseMapper().findAuthResListByRoleId(role.getId());
        if (CollectionUtils.isNotEmpty(authResDBList)) {
            List<String> authKeys = authResDBList.stream().map(data -> data.getId().toString()).collect(Collectors.toList());
            roleAuthResTreeVo.setAuthKeys(authKeys);
        }

        return roleAuthResTreeVo;
    }

    private void setTreeChildren(List<AuthRes> childDataList, List<TreeVo> children, TreeVo treeVo){
        for (AuthRes authRes : childDataList) {
            if (authRes.getParentId() != Long.valueOf(treeVo.getValue()).longValue()) {
                continue;
            }
            TreeVo childTreeVo = new TreeVo();
            childTreeVo.setTitle(authRes.getName());
            childTreeVo.setValue(authRes.getId().toString());
            childTreeVo.setKey(authRes.getId().toString());
            children.add(childTreeVo);

            List<TreeVo> subChildren = new ArrayList<>();
            setTreeChildren(childDataList,subChildren,childTreeVo);
        }
        if(children.size() > 0){
            treeVo.setChildren(children);
        }
    }


    public AuthRes saveAuthRes(AuthRes authRes) {
        Long parentId = authRes.getParentId();
//        if (parentId == null) {
//            parentId = 0L;
//        }
        String parentCode = "0";
        if(parentId != 0){
            parentCode = this.findById(parentId).getCode();
        }
        authRes.setParentId(parentId);
        String no = serialNumberService.getSerialNumber("sys_auth_res", parentCode);
        authRes.setCode(no);
        this.save(authRes);
        return authRes;
    }

    public AuthRes updateAuthRes(AuthRes authRes){
        Long parentId = authRes.getParentId();
        if(parentId.longValue() == authRes.getId()){
            throw new BizException("不能作为自己的父级",false);
        }
        AuthRes oldBean = this.findById(authRes.getId());
        Long oldParentId = oldBean.getParentId();
        BeanUtils.beanCopy(authRes,oldBean);
        if(oldParentId == parentId.longValue()){  //直接修改属性
            this.save(oldBean);
        }else{  //修改了父级，则涉及到的编码包括该级的下一级编码都得改
            String parentCode = "0";
            if(parentId != 0){
                parentCode = this.findById(parentId).getCode();
            }
            String no = serialNumberService.getSerialNumber("sys_auth_res", parentCode);
            oldBean.setCode(no);
            this.save(oldBean);

            //查询下一级修改
            updateChildrenForNo(oldBean.getId(),no);
        }
        return oldBean;
    }

    private void updateChildrenForNo(Long parentId,String parentNo){
        List<AuthRes> childAuthResList = this.getChildrenByParentId(parentId);
        if(CollectionUtils.isNotEmpty(childAuthResList)){
            for (AuthRes childAuthRes : childAuthResList) {
                String childNo = serialNumberService.getSerialNumber("sys_auth_res", parentNo);
                childAuthRes.setCode(childNo);
                this.save(childAuthRes);

                updateChildrenForNo(childAuthRes.getId(),childNo);

            }
        }
    }


    public AuthRes menuParamToAuthRes(MenuParam menuParam) {
        AuthRes authRes = new AuthRes();
//        if(menuParam.getId() != null){
//            authRes = this.findById(menuParam.getId());
//        }
        authRes.setId(menuParam.getId());
        authRes.setName(menuParam.getName());
        authRes.setUrl(menuParam.getPath());
        authRes.setTplUrl(menuParam.getComponent());
        authRes.setMenu(menuParam.getMenu());
        authRes.setAppType(menuParam.getAppType());
        authRes.setIcon(menuParam.getIcon());
        authRes.setDescription(menuParam.getDescription());
        Long parentId = menuParam.getParentId();
        if (parentId == null) {
            parentId = 0L;
        }
        authRes.setParentId(parentId);
//        String type = "0";
//        if(StringUtils.isEmpty(authRes.getCode()) || authRes.getParentId() != parentId.longValue() ){
//            AuthRes parentAuthRes = this.findById(parentId);
//            type = parentAuthRes.getCode();
//            String no = serialNumberService.getSerialNumber("sys_auth_res", type);
//            authRes.setCode(no);
//        }
        authRes.setOrderNo(menuParam.getOrderNo() == null ? 1 : menuParam.getOrderNo());
        authRes.setLevel(menuParam.getParentId() == null || menuParam.getParentId() == 0L? 0 : 1);
        authRes.setStatus(1);
        authRes.setDisplay(true);
        authRes.setActionId("");
        authRes.setAuthCheck(true);
        authRes.setRiskCheck(false);
        authRes.setRepeatCheck(false);
        return authRes;
    }

    public void copy(List<Long> authResIds){
        for (Long authResId : authResIds) {
            AuthRes authRes = this.findById(authResId);
            AuthRes copyAuthRes = BeanUtils.beanCopy(authRes, AuthRes.class);
            copyAuthRes.setId(null);
            copyAuthRes.setName(authRes.getName()+"_copy");
            copyAuthRes.setUrl(authRes.getUrl()+"_copy");
            copyAuthRes.setTplUrl(authRes.getTplUrl()+"_copy");
            this.saveAuthRes(copyAuthRes);
        }


    }

    public int del(List<Long> ids){
        for (Long id : ids) {
            AuthRes authRes = this.findById(id);
            this.getBaseMapper().delByCodeLike(authRes.getCode());
        }
        return 1;
    }








}
